﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
using DataAccessLayer;

namespace BusinessLogicLayer
{
    public class clsSettings
    {
        #region Properties
        private Uri ExecutionFolderPath { get; set; }
        public Uri ExecutionFilePath { get; set; }
        public Int32 DatabaseVersion_Database { get; set; }
        public Int32 DatabaseVersion_Program = 7;
        public enumDatabaseChoice DatabaseChoice { get; set; }
        public String UserName_Database { get; set; }
        public String Password_Database { get; set; }
        public String DatabaseName { get; set; }
        public String DatabaseAddress { get; set; }
        public clsUser User_Login { get; set; }
        public enumLoginMethod LoginMethod { get; set; }
        
        public enum enumDatabaseChoice
        {
            MicrosoftSQLServer2000,
            MySQLServer
        }
        public enum enumLoginMethod
        {
            AskForPassword,
            LoginAutomatically
        }
        #endregion

        #region Constructors
        /// <summary>
        /// Get the settings from the file or create the file.
        /// </summary>
        /// <param name="pPathExecution">Execution path of the main application.</param>
        public clsSettings(String pPathExecution)
        {
            this.ExecutionFilePath = ConvertPathToUri(pPathExecution);
        }
        #endregion

        #region Events
        #endregion

        #region Public methods
        /// <summary>
        /// Saves the login settings.
        /// </summary>
        /// <param name="pLoginMethod">The login method configuration.</param>
        /// <param name="pUser">The user login configuration.</param>
        /// <returns>The state of success.</returns>
        public Boolean SaveLoginSettings(enumLoginMethod pLoginMethod)
        {
            this.LoginMethod = pLoginMethod;
            return WriteSettings();
        }

        /// <summary>
        /// Saves the settings.
        /// </summary>
        /// <returns>The state of success.</returns>
        public Boolean SaveSettings(enumDatabaseChoice pSelectedDatabase, String pDbAddress, String pDbUserName, String pDbPassword, String pDatabaseName)
        {
            //Insert all the configurations to the settings class.
            this.DatabaseChoice = pSelectedDatabase;
            this.DatabaseName = pDatabaseName;
            this.UserName_Database = pDbUserName;
            this.Password_Database = pDbPassword;
            this.DatabaseAddress = pDbAddress;

            //Save all the configurations.
            return WriteSettings();
        }

        /// <summary>
        /// Determines if a configuration file exists.
        /// </summary>
        /// <returns>The state of an existing configuration.</returns>
        public Boolean ConfigurationFileExists()
        {
            clsFileAccess FileAccess = new clsFileAccess(GetSettingsFilePath());
            
            if (FileAccess.FileExists())
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        /// <summary>
        /// Loads the settings of the settings file and stores the values into the properties.
        /// </summary>
        /// <returns>The state of success.</returns>
        public Boolean LoadSettings()
        {
            try
            {
                Boolean Settings_Element = false;
                String Settings_ElementName = "Settings";
                String ActualElementName = "";

                using (XmlReader reader = XmlReader.Create(new StringReader(GetSettingsFileContent().Replace("\r\n", ""))))
                {
                    while (reader.Read())
                    {
                        //Determine if the section "Settings" is readout.
                        if (reader.NodeType == XmlNodeType.Element)
                        {
                            if (reader.Name == Settings_ElementName)
                            {
                                Settings_Element = true;
                            }
                        }

                        //Only read settings if in section "Settings".
                        if (Settings_Element)
                        {
                            switch (reader.NodeType)
                            {
                                case XmlNodeType.Element:
                                    if (reader.Name != Settings_ElementName)
                                    {
                                        ActualElementName = reader.Name;
                                    }
                                    break;
                                case XmlNodeType.Text:
                                    //Set the values of the configuration file into the properties.
                                    switch (ActualElementName)
                                    {
                                        case "DatabaseChoice":
                                            SetDatabaseChoice(reader.Value);
                                            break;
                                        case "UserID_Login":
                                            FillUser(Convert.ToInt32(reader.Value));
                                            break;
                                        case "Password_Login":
                                            FillUser(reader.Value);
                                            break;
                                        case "UserName_Database":
                                            this.UserName_Database = reader.Value;
                                            break;
                                        case "Password_Database":
                                            this.Password_Database = reader.Value;
                                            break;
                                        case "DatabaseName":
                                            this.DatabaseName = reader.Value;
                                            break;
                                        case "DatabaseAddress":
                                            this.DatabaseAddress = reader.Value;
                                            break;
                                        default:
                                            break;
                                    }
                                    break;
                                case XmlNodeType.EndElement:
                                    //Check, if still in section "Settings".
                                    if (reader.Name == Settings_ElementName)
                                    {
                                        Settings_Element = false;
                                    }
                                    ActualElementName = "";
                                    break;
                                default:
                                    break;
                            }

                        }
                    }
                }
                return true;
            }
            catch
            {
                //An error accrued.
                return false;
            }
        }

        public Boolean WriteSettings()
        {
            StringBuilder output = new StringBuilder();
            XmlWriterSettings ws = new XmlWriterSettings();
            ws.Indent = true;
            using (XmlWriter writer = XmlWriter.Create(output, ws))
            {
                writer.WriteStartElement("Settings");

                //Generate collection of parameters. All the parameters embraced here are included in the output XML.
                ArrayList Settings = new ArrayList();
                Settings.Add(new clsAttribute("DatabaseChoice", this.DatabaseChoice.ToString()));
                Settings.Add(new clsAttribute("DatabaseAddress", this.DatabaseAddress));
                Settings.Add(new clsAttribute("DatabaseName", this.DatabaseName));
                Settings.Add(new clsAttribute("UserName_Database", this.UserName_Database));
                Settings.Add(new clsAttribute("Password_Database", this.Password_Database));
                if (this.LoginMethod == enumLoginMethod.LoginAutomatically)
                {
                    Settings.Add(new clsAttribute("UserID_Login", this.User_Login.ID.ToString()));
                    Settings.Add(new clsAttribute("Password_Login", this.User_Login.Password));
                }

                foreach(clsAttribute Attr in Settings)
                {
                    if (Attr.AttributeValue != "")
                    {
                        writer.WriteStartElement(Attr.AttributeName);
                        writer.WriteString(Attr.AttributeValue);
                        writer.WriteEndElement();
                    }
                }

                writer.WriteFullEndElement();
            }
            return SaveSettingsToFile(output.ToString());
        }
        #endregion

        #region Private methods
        /// <summary>
        /// Set the property DatabaseChoice
        /// </summary>
        /// <param name="pValue">The database</param>
        /// <returns></returns>
        private void SetDatabaseChoice(String pValue)
        {
            if (pValue == enumDatabaseChoice.MicrosoftSQLServer2000.ToString())
            {
                this.DatabaseChoice = enumDatabaseChoice.MicrosoftSQLServer2000;
            }
            else if (pValue == enumDatabaseChoice.MySQLServer.ToString())
            {
                this.DatabaseChoice = enumDatabaseChoice.MySQLServer;
            }
            else
            {
                throw new ArgumentException("Error 5");
            }
        }

        /// <summary>
        /// Convert a path into the Uri format.
        /// </summary>
        /// <param name="pPath">The path to be converted.</param>
        /// <returns>The converted path.</returns>
        private Uri ConvertPathToUri(String pPath)
        {
            return new Uri(pPath);
        }

        /// <summary>
        /// Returns the execution folder of a file.
        /// </summary>
        /// <returns>The execution folder.</returns>
        private Uri GetExecutionFolderPath()
        {
            if (this.ExecutionFolderPath == null)
            {
                String[] CompleteAddress = this.ExecutionFilePath.LocalPath.Split('\\');
                String FolderPath = "";
                if (CompleteAddress.Length > 0)
                {
                    //Only on Windows machines starting on i = 1. On Linux it would be probably i = 0.
                    for (Int32 i = 0; i < (CompleteAddress.Length - 1); i++)
                    {
                        //Only possible on Windows machines. On Linux it would be "/".
                        FolderPath += CompleteAddress[i] + "\\";
                    }
                }
                this.ExecutionFolderPath = ConvertPathToUri(FolderPath);
            }
            return this.ExecutionFolderPath;
        }

        /// <summary>
        /// Store the login user id.
        /// </summary>
        /// <param name="pID">The login user id.</param>
        private void FillUser(Int32 pID)
        {
            if (this.User_Login == null)
            {
                this.User_Login = new clsUser();
            }
            this.User_Login.ID = pID;
        }

        /// <summary>
        /// Store the login user password.
        /// </summary>
        /// <param name="pPassword">The login user password.</param>
        private void FillUser(String pPassword)
        {
            if (this.User_Login == null)
            {
                this.User_Login = new clsUser();
            }
            this.User_Login.Password = pPassword;
        }

        /// <summary>
        /// Gets the path of the settings file.
        /// </summary>
        /// <returns>The path of the settings file.</returns>
        private Uri GetSettingsFilePath()
        {
            return ConvertPathToUri(GetExecutionFolderPath().LocalPath + "GlassesSettings.xml");
        }

        /// <summary>
        /// Gets the content of the settings file.
        /// </summary>
        /// <returns>The content of the settings file.</returns>
        private String GetSettingsFileContent()
        {
            return File.ReadAllText(GetSettingsFilePath().LocalPath);
        }

        /// <summary>
        /// Saves the settings to the configuration file.
        /// </summary>
        /// <param name="pContent"></param>
        /// <returns></returns>
        private Boolean SaveSettingsToFile(String pContent)
        {
            try
            {
                File.WriteAllText(GetSettingsFilePath().LocalPath, pContent);
                return true;
            }
            catch
            {
                return false;
            }
        }
        #endregion
    }
}
